home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / src / toplev.cc < prev    next >
C/C++ Source or Header  |  1997-06-25  |  25KB  |  1,101 lines

  1. /*
  2.  
  3. Copyright (C) 1996 John W. Eaton
  4.  
  5. This file is part of Octave.
  6.  
  7. Octave is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. Octave is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Octave; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. */
  22.  
  23. /* Modified by Klaus Gebhardt, 1996 - 1997 */
  24.  
  25. #ifdef HAVE_CONFIG_H
  26. #include <config.h>
  27. #endif
  28.  
  29. #include <cassert>
  30. #include <csetjmp>
  31. #include <csignal>
  32. #include <cstdlib>
  33. #include <cstring>
  34. #include <ctime>
  35.  
  36. #include <string>
  37.  
  38. #include <fstream.h>
  39. #include <iostream.h>
  40. #include <strstream.h>
  41.  
  42. #ifdef HAVE_UNISTD_H
  43. #ifdef HAVE_SYS_TYPES_H
  44. #include <sys/types.h>
  45. #endif
  46. #include <unistd.h>
  47. #endif
  48.  
  49. #include "lo-error.h"
  50. #include "lo-mappers.h"
  51. #include "str-vec.h"
  52.  
  53. #include "builtins.h"
  54. #include <defaults.h>
  55. #include "defun.h"
  56. #include "dynamic-ld.h"
  57. #include "error.h"
  58. #include "file-io.h"
  59. #include "help.h"
  60. #include "input.h"
  61. #include "lex.h"
  62. #include <oct-conf.h>
  63. #include "oct-hist.h"
  64. #include "oct-map.h"
  65. #include "pager.h"
  66. #include "parse.h"
  67. #include "pathsearch.h"
  68. #include "procstream.h"
  69. #include "ov.h"
  70. #include "pt-fvc.h"
  71. #include "pt-misc.h"
  72. #include "pt-plot.h"
  73. #include "sighandlers.h"
  74. #include "sysdep.h"
  75. #include "syswait.h"
  76. #include "toplev.h"
  77. #include "unwind-prot.h"
  78. #include "utils.h"
  79. #include "variables.h"
  80. #include <version.h>
  81.  
  82. #ifdef __EMX__
  83. extern "C"
  84. {
  85. #include <process.h>
  86.   int _IO_system (const char *, int);
  87. }
  88. #endif
  89.  
  90. // argv[0] for this program.
  91. string Vprogram_invocation_name;
  92.  
  93. // Cleaned-up name of this program, not including path information.
  94. string Vprogram_name;
  95.  
  96. // Login name for user running this program.
  97. string Vuser_name;
  98.  
  99. // Name of the host we are running on.
  100. string Vhost_name;
  101.  
  102. // User's home directory.
  103. string Vhome_directory;
  104.  
  105. // Nonzero means we print 
  106. static bool Vdefault_eval_print_flag = true;
  107.  
  108. // Nonzero means we're breaking out of a loop or function body.
  109. extern int breaking;
  110.  
  111. // Nonzero means we're returning from a function.
  112. extern int returning;
  113.  
  114. // Nonzero means we are using readline.
  115. // (--no-line-editing)
  116. #if defined (USE_READLINE)
  117. int using_readline = 1;
  118. #else
  119. int using_readline = 0;
  120. #endif
  121.  
  122. #if defined (USE_READLINE)
  123. // This is from readline's rltty.c:
  124. extern "C" void rl_deprep_terminal (void);
  125. #endif
  126.  
  127. // Nonzero means we printed messages about reading startup files.
  128. int reading_startup_message_printed = 0;
  129.  
  130. // Command number, counting from the beginning of this session.
  131. int current_command_number = 1;
  132.  
  133. // Nonzero means we are exiting via the builtin exit or quit functions.
  134. int quitting_gracefully = 0;
  135.  
  136. // Current command to execute.
  137. tree_statement_list *global_command = 0;
  138.  
  139. // Pointer to function that is currently being evaluated.
  140. tree_function *curr_function = 0;
  141.  
  142. // Nonzero means input is coming from startup file.
  143. int input_from_startup_file = 0;
  144.  
  145. // Nonzero means that input is coming from a file that was named on
  146. // the command line.
  147. int input_from_command_line_file = 1;
  148.  
  149. // Top level context (?)
  150. jmp_buf toplevel;
  151.  
  152. void
  153. parse_and_execute (FILE *f, int print)
  154. {
  155.   volatile octave_interrupt_handler old_interrupt_handler
  156.     = octave_ignore_interrupts ();
  157.  
  158.   volatile jmp_buf old_toplevel = toplevel;
  159.  
  160.   begin_unwind_frame ("parse_and_execute");
  161.  
  162.   YY_BUFFER_STATE old_buf = current_buffer ();
  163.   YY_BUFFER_STATE new_buf = create_buffer (f);
  164.  
  165.   add_unwind_protect (restore_input_buffer, (void *) old_buf);
  166.   add_unwind_protect (delete_input_buffer, (void *) new_buf);
  167.  
  168.   switch_to_buffer (new_buf);
  169.  
  170.   unwind_protect_int (using_readline);
  171.   unwind_protect_int (input_from_command_line_file);
  172.  
  173.   using_readline = 0;
  174.   input_from_command_line_file = 0;
  175.  
  176.   unwind_protect_ptr (curr_sym_tab);
  177.  
  178.   if (setjmp(toplevel) == 0)
  179.     {
  180.       octave_set_interrupt_handler (old_interrupt_handler);
  181.  
  182.       int retval;
  183.       do
  184.     {
  185.       reset_parser ();
  186.  
  187.       retval = yyparse ();
  188.  
  189.       if (retval == 0 && global_command)
  190.         {
  191.           global_command->eval (print);
  192.  
  193.           delete global_command;
  194.  
  195.           global_command = 0;
  196.  
  197.           bool quit = (returning || breaking);
  198.  
  199.           if (returning)
  200.         returning = 0;
  201.  
  202.           if (breaking)
  203.         breaking--;
  204.  
  205.           if (error_state)
  206.         {
  207.           error ("near line %d of file `%s'", input_line_number,
  208.              curr_fcn_file_full_name.c_str ());
  209.  
  210.           break;
  211.         }
  212.  
  213.           if (quit)
  214.         break;
  215.         }
  216.     }
  217.       while (retval == 0);
  218.     }
  219.   else  error ("script executing interrupted ...");
  220.  
  221.   run_unwind_frame ("parse_and_execute");
  222.  
  223.   octave_ignore_interrupts ();
  224.   toplevel = old_toplevel;
  225.   octave_set_interrupt_handler (old_interrupt_handler);
  226. }
  227.  
  228. static void
  229. safe_fclose (void *f)
  230. {
  231.   if (f)
  232.     fclose ((FILE *) f);
  233. }
  234.  
  235. void
  236. parse_and_execute (const string& s, int print, int verbose,
  237.            const char *warn_for)
  238. {
  239.   volatile octave_interrupt_handler old_interrupt_handler
  240.     = octave_ignore_interrupts ();
  241.  
  242.   begin_unwind_frame ("parse_and_execute_2");
  243.  
  244.   unwind_protect_int (reading_script_file);
  245.   unwind_protect_str (curr_fcn_file_full_name);
  246.  
  247.   reading_script_file = 1;
  248.   curr_fcn_file_full_name = s;
  249.  
  250.   FILE *f = get_input_from_file (s, 0);
  251.  
  252.   if (f)
  253.     {
  254.       add_unwind_protect (safe_fclose, (void *) f);
  255.  
  256.       unwind_protect_int (input_line_number);
  257.       unwind_protect_int (current_input_column);
  258.  
  259.       input_line_number = 0;
  260.       current_input_column = 1;
  261.  
  262.       if (verbose)
  263.     {
  264.       cout << "reading commands from " << s << " ... ";
  265.       reading_startup_message_printed = 1;
  266.       cout.flush ();
  267.     }
  268.  
  269.       parse_and_execute (f, print);
  270.  
  271.       if (verbose)
  272.     cout << "done." << endl;
  273.     }
  274.   else if (warn_for)
  275.     error ("%s: unable to open file `%s'", warn_for, s.c_str ());
  276.  
  277.   run_unwind_frame ("parse_and_execute_2");
  278.  
  279.   octave_set_interrupt_handler (old_interrupt_handler);
  280. }
  281.  
  282. int
  283. main_loop (void)
  284. {
  285.   // Allow the user to interrupt us without exiting.
  286.  
  287.   octave_save_signal_mask ();
  288.  
  289.   if (setjmp (toplevel) != 0)
  290.     {
  291. #if defined (__EMX__) && defined (OS2)
  292.       run_all_unwind_protects ();
  293. #endif
  294.  
  295.       raw_mode (0);
  296.  
  297.       cout << "\n";
  298.  
  299.       octave_restore_signal_mask ();
  300.     }
  301.  
  302.   can_interrupt = 1;
  303.  
  304.   octave_catch_interrupts ();
  305.  
  306.   // The big loop.
  307.  
  308.   int retval;
  309.   do
  310.     {
  311. #ifdef __EMX__
  312.       can_interrupt = 1;
  313.       octave_catch_interrupts ();
  314. #endif
  315.  
  316.       curr_sym_tab = top_level_sym_tab;
  317.  
  318.       reset_parser ();
  319.  
  320.       retval = yyparse ();
  321.  
  322.       if (retval == 0 && global_command)
  323.     {
  324.       global_command->eval (1);
  325.  
  326.       delete global_command;
  327.  
  328.       global_command = 0;
  329.  
  330.       if (! (interactive || forced_interactive
  331.          || really_forced_interactive))
  332.         {
  333.           bool quit = (returning || breaking);
  334.  
  335.           if (returning)
  336.         returning = 0;
  337.  
  338.           if (breaking)
  339.         breaking--;
  340.  
  341.           if (quit)
  342.         break;
  343.         }
  344.  
  345.       if (error_state)
  346.         {
  347.           if (! (interactive || forced_interactive
  348.              || really_forced_interactive))
  349.         break;
  350.         }
  351.         else
  352.         {
  353.           if (octave_completion_matches_called)
  354.         octave_completion_matches_called = false;        
  355.           else
  356.         current_command_number++;
  357.         }
  358.     }
  359.     }
  360.   while (retval == 0);
  361.  
  362.   return retval;
  363. }
  364.  
  365. DEFUN (source, args, ,
  366.   "source (FILE)\n\
  367. \n\
  368. Parse and execute the contents of FILE.  Like executing commands in a\n\
  369. script file but without requiring the file to be named `FILE.m'.")
  370. {
  371.   octave_value_list retval;
  372.  
  373.   int nargin = args.length ();
  374.  
  375.   if (nargin == 1)
  376.     {
  377.       string file = args(0).string_value ();
  378.  
  379.       if (! error_state)
  380.     {
  381.       file = oct_tilde_expand (file);
  382.  
  383.       parse_and_execute (file, 1, 0, "source");
  384.  
  385.       if (error_state)
  386.         error ("source: error sourcing file `%s'", file.c_str ());
  387.     }
  388.       else
  389.     error ("source: expecting file name as argument");
  390.     }
  391.   else
  392.     print_usage ("source");
  393.  
  394.   return retval;
  395. }
  396.  
  397. // Fix up things before exiting.
  398.  
  399. void
  400. clean_up_and_exit (int retval)
  401. {
  402. #if defined (USE_READLINE)
  403.   rl_deprep_terminal ();
  404. #else
  405.   raw_mode (0);
  406. #endif
  407.  
  408.   octave_command_history.clean_up_and_save ();
  409.  
  410.   close_plot_stream ();
  411.  
  412.   close_files ();
  413.  
  414.   cleanup_tmp_files ();
  415.  
  416.   if (!quitting_gracefully &&
  417.       (interactive || forced_interactive || really_forced_interactive))
  418.     cout << "\n";
  419.  
  420.   if (retval == EOF)
  421.     retval = 0;
  422.  
  423. #if defined (__EMX__)
  424.   _sleep2 (500);
  425. #endif
  426.  
  427.   exit (retval);
  428.  
  429.   // This is bogus but should prevent g++ from giving a warning saying
  430.   // that this volatile function does return.
  431.  
  432.   panic_impossible ();
  433. }
  434.  
  435. DEFUN_TEXT (casesen, args, ,
  436.   "casesen [on|off]")
  437. {
  438.   octave_value_list retval;
  439.  
  440.   int argc = args.length () + 1;
  441.  
  442.   string_vector argv = args.make_argv ("casesen");
  443.  
  444.   if (error_state)
  445.     return retval;
  446.  
  447.   if (argc == 1 || (argc > 1 && argv[1] == "off"))
  448.     warning ("casesen: sorry, Octave is always case sensitive");
  449.   else if (argc > 1 && argv[1] == "on")
  450.     ; // ok.
  451.   else
  452.     print_usage ("casesen");
  453.  
  454.   return retval;
  455. }
  456.  
  457. DEFUN (computer, args, nargout,
  458.   "computer ():\n\
  459. \n\
  460. Have Octave ask the system, \"What kind of computer are you?\"")
  461. {
  462.   octave_value_list retval;
  463.  
  464.   int nargin = args.length ();
  465.  
  466.   if (nargin != 0)
  467.     warning ("computer: ignoring extra arguments");
  468.  
  469.   string msg;
  470.  
  471.   if (strcmp (TARGET_HOST_TYPE, "unknown") == 0)
  472.     msg = "Hi Dave, I'm a HAL-9000";
  473.   else
  474.     msg = TARGET_HOST_TYPE;
  475.  
  476.   if (nargout == 0)
  477.     octave_stdout << msg << "\n";
  478.   else
  479.     retval = msg;
  480.  
  481.   return retval;
  482. }
  483.  
  484. DEFUN (quit, args, ,
  485.   "quit (STATUS): exit Octave gracefully, returning STATUS to the system.\n\
  486. \n\
  487. STATUS should be an integer value.  If STATUS is missing, 0 is assumed.")
  488. {
  489.   octave_value_list retval;
  490.  
  491.   int exit_status = 0;
  492.  
  493.   quitting_gracefully = 1;
  494.  
  495.   int nargin = args.length ();
  496.  
  497.   if (nargin > 0)
  498.     {
  499.       // XXX FIXME XXX -- need a safe uniform way to do this.
  500.  
  501.       double tmp = args(0).double_value ();
  502.  
  503.       if (! error_state && ! xisnan (tmp))
  504.     exit_status = NINT (tmp);
  505.     }
  506.  
  507.   clean_up_and_exit (exit_status);
  508.  
  509.   return retval;
  510. }
  511.  
  512. DEFALIAS (exit, quit);
  513.  
  514. DEFUN (warranty, , ,
  515.   "warranty (): describe copying conditions")
  516. {
  517.   octave_value_list retval;
  518.  
  519.   octave_stdout << "\n" OCTAVE_NAME_VERSION_AND_COPYRIGHT "\n\n\
  520. This program is free software; you can redistribute it and/or modify\n\
  521. it under the terms of the GNU General Public License as published by\n\
  522. the Free Software Foundation; either version 2 of the License, or\n\
  523. (at your option) any later version.\n\
  524. \n\
  525. This program is distributed in the hope that it will be useful,\n\
  526. but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
  527. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
  528. GNU General Public License for more details.\n\
  529. \n\
  530. You should have received a copy of the GNU General Public License\n\
  531. along with this program. If not, write to the Free Software\n\
  532. Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\
  533. \n";
  534.  
  535.   return retval;
  536. }
  537.  
  538. // XXX FIXME XXX -- this may not be the best place for these...
  539.  
  540. octave_value_list
  541. feval (const octave_value_list& args, int nargout)
  542. {
  543.   octave_value_list retval;
  544.  
  545.   tree_fvc *fcn = is_valid_function (args(0), "feval", 1);
  546.   if (fcn)
  547.     {
  548.       int tmp_nargin = args.length () - 1;
  549.       octave_value_list tmp_args;
  550.       tmp_args.resize (tmp_nargin);
  551.       for (int i = 0; i < tmp_nargin; i++)
  552.     tmp_args(i) = args(i+1);
  553.       retval = fcn->eval (0, nargout, tmp_args);
  554.     }
  555.  
  556.   return retval;
  557. }
  558.  
  559. DEFUN (feval, args, nargout,
  560.   "feval (NAME, ARGS, ...)\n\
  561. \n\
  562. evaluate NAME as a function, passing ARGS as its arguments")
  563. {
  564.   octave_value_list retval;
  565.  
  566.   int nargin = args.length ();
  567.  
  568.   if (nargin > 0)
  569.     retval = feval (args, nargout);
  570.   else
  571.     print_usage ("feval");
  572.  
  573.   return retval;
  574. }
  575.  
  576. static octave_value_list
  577. eval_string (const string& s, int print, int& parse_status,
  578.          int nargout) 
  579. {
  580.   begin_unwind_frame ("eval_string");
  581.  
  582.   unwind_protect_int (get_input_from_eval_string);
  583.   unwind_protect_int (input_from_command_line_file);
  584.   unwind_protect_ptr (global_command);
  585.   unwind_protect_str (current_eval_string);
  586.  
  587.   get_input_from_eval_string = 1;
  588.   input_from_command_line_file = 0;
  589.   current_eval_string = s;
  590.  
  591.   YY_BUFFER_STATE old_buf = current_buffer ();
  592.   YY_BUFFER_STATE new_buf = create_buffer (0);
  593.  
  594.   add_unwind_protect (restore_input_buffer, (void *) old_buf);
  595.   add_unwind_protect (delete_input_buffer, (void *) new_buf);
  596.  
  597.   switch_to_buffer (new_buf);
  598.  
  599.   unwind_protect_ptr (curr_sym_tab);
  600.  
  601.   reset_parser ();
  602.  
  603.   parse_status = yyparse ();
  604.  
  605.   // Important to reset the idea of where input is coming from before
  606.   // trying to eval the command we just parsed -- it might contain the
  607.   // name of an function file that still needs to be parsed!
  608.  
  609.   tree_statement_list *command = global_command;
  610.  
  611.   run_unwind_frame ("eval_string");
  612.  
  613.   octave_value_list retval;
  614.  
  615.   if (parse_status == 0 && command)
  616.     {
  617.       retval = command->eval (print, nargout);
  618.       delete command;
  619.     }
  620.  
  621.   return retval;
  622. }
  623.  
  624. octave_value
  625. eval_string (const string& s, int print, int& parse_status)
  626. {
  627.   octave_value retval;
  628.  
  629.   octave_value_list tmp = eval_string (s, print, parse_status, 1);
  630.  
  631.   retval = tmp(0);
  632.  
  633.   return retval;
  634. }
  635.  
  636. static octave_value_list
  637. eval_string (const octave_value& arg, int print, int& parse_status,
  638.          int nargout)
  639. {
  640.   string s = arg.string_value ();
  641.  
  642.   if (error_state)
  643.     {
  644.       error ("eval: expecting string argument");
  645.       return -1.0;
  646.     }
  647.  
  648.   return eval_string (s, print, parse_status, nargout);
  649. }
  650.  
  651. DEFUN (eval, args, nargout,
  652.   "eval (TRY, CATCH)\n\
  653. \n\
  654. Evaluate the string TRY as octave code.  If that fails, evaluate the\n\
  655. string CATCH.")
  656. {
  657.   octave_value_list retval;
  658.  
  659.   int nargin = args.length ();
  660.  
  661.   if (nargin > 0)
  662.     {
  663.       begin_unwind_frame ("Feval");
  664.  
  665.       if (nargin > 1)
  666.     {
  667.       unwind_protect_int (buffer_error_messages);
  668.       buffer_error_messages = 1;
  669.     }
  670.  
  671.       int parse_status = 0;
  672.  
  673.       retval = eval_string (args(0), Vdefault_eval_print_flag,
  674.                 parse_status, nargout);
  675.  
  676.       if (nargin > 1 && (parse_status != 0 || error_state))
  677.     {
  678.       error_state = 0;
  679.  
  680.       // Set up for letting the user print any messages from
  681.       // errors that occurred in the first part of this eval().
  682.  
  683.       buffer_error_messages = 0;
  684.       bind_global_error_variable ();
  685.       add_unwind_protect (clear_global_error_variable, 0);
  686.  
  687.       eval_string (args(1), 0, parse_status, nargout);
  688.  
  689.       retval = octave_value_list ();
  690.     }
  691.  
  692.       run_unwind_frame ("Feval");
  693.     }
  694.   else
  695.     print_usage ("eval");
  696.  
  697.   return retval;
  698. }
  699.  
  700. // Execute a shell command.
  701.  
  702. static int cmd_status = 0;
  703.  
  704. static void
  705. cmd_death_handler (pid_t, int status)
  706. {
  707.   cmd_status = status;
  708. }
  709.  
  710. static void
  711. cleanup_iprocstream (void *p)
  712. {
  713.   iprocstream *cmd = (iprocstream *) p;
  714.  
  715.   octave_child_list::remove (cmd->pid ());
  716.  
  717.   delete cmd;
  718. }
  719.  
  720. static octave_value_list
  721. run_command_and_return_output (const string& cmd_str)
  722. {
  723.   octave_value_list retval;
  724.  
  725.   iprocstream *cmd = new iprocstream (cmd_str.c_str ());
  726.  
  727.   cmd_status = -1;
  728.  
  729.   if (cmd)
  730.     {
  731.       octave_child_list::insert (cmd->pid (), cmd_death_handler);
  732.  
  733.       add_unwind_protect (cleanup_iprocstream, cmd);
  734.  
  735.       if (*cmd)
  736.     {
  737.       ostrstream output_buf;
  738.  
  739.       char ch;
  740.       while (cmd->get (ch))
  741.         output_buf.put (ch);
  742.  
  743.       cmd->close ();
  744.  
  745.       // One way or another, cmd_death_handler should be called
  746.       // when the process exits, and it will save the exit status
  747.       // of the command in cmd_status.
  748.  
  749.       // The value in cmd_status is as returned by waitpid.  If
  750.       // the process exited normally, extract the actual exit
  751.       // status of the command.  Otherwise, return 127 as a
  752.       // failure code.
  753.  
  754.       if (WIFEXITED (cmd_status))
  755.         cmd_status = WEXITSTATUS (cmd_status);
  756.       else
  757.         cmd_status = 127;
  758.  
  759.       output_buf << ends;
  760.  
  761.       char *msg = output_buf.str ();
  762.  
  763.       retval(1) = (double) cmd_status;
  764.       retval(0) = msg;
  765.  
  766.       delete [] msg;
  767.     }
  768.  
  769.       run_unwind_protect ();
  770.     }
  771.   else
  772.     error ("unable to start subprocess for `%s'", cmd_str.c_str ());
  773.  
  774.   return retval;
  775. }
  776.  
  777. DEFUN (system, args, nargout,
  778.   "system (STRING [, RETURN_OUTPUT] [, TYPE])\n\
  779. \n\
  780. Execute the shell command specified by STRING.\n\
  781. \n\
  782. If TYPE is \"async\", the process is started in the background and the\n\
  783. pid of the child proces is returned immediately.  Otherwise, the\n\
  784. process is started, and Octave waits until it exits.  If TYPE argument\n\
  785. is omitted, a value of \"sync\" is assumed.\n\
  786. \n\
  787. If NARGIN == 2 (the actual value of RETURN_OUTPUT is irrelevant) and\n\
  788. the subprocess is started synchronously, or if system() is called with\n\
  789. NARGIN == 1 and NARGOUT > 0, the output from the command is returned.\n\
  790. Otherwise, if the subprocess is executed synchronously, it's output is\n\
  791. sent to the standard output.  To send the output of a command executed\n\
  792. with system() through the pager, use a command like\n\
  793. \n\
  794.    disp (system (CMD, 1));\n\
  795. \n\
  796. or\n\
  797. \n\
  798.    printf (\"%s\\n\", system (CMD, 1));")
  799. {
  800.   octave_value_list retval;
  801.  
  802.   int nargin = args.length ();
  803.  
  804.   if (nargin > 0 && nargin < 4)
  805.     {
  806.       bool return_output = (nargout > 0 || nargin > 1);
  807.  
  808.       string cmd_str = args(0).string_value ();
  809.  
  810. #if defined (__EMX__) && defined (OS2)
  811.       enum exec_type { sync, async, pm };
  812. #else
  813.       enum exec_type { sync, async };
  814. #endif
  815.  
  816.       exec_type type = sync;
  817.  
  818.       if (! error_state)
  819.     {
  820.       if (nargin > 2)
  821.         {
  822.           string type_str = args(2).string_value ();
  823.  
  824.           if (! error_state)
  825.         {
  826.           if (type_str == "sync")
  827.             type = sync;
  828.           else if (type_str == "async")
  829.             type = async;
  830. #if defined (__EMX__) && defined (OS2)
  831.           else if (type_str == "pm")
  832.             type = pm;
  833.           else
  834.             error ("system: third arg must be \"sync\" , \"async\""
  835.                "or \"pm\"");
  836. #else
  837.           else
  838.             error ("system: third arg must be \"sync\" or \"async\"");
  839. #endif
  840.         }
  841.           else
  842.         error ("system: third argument must be a string");
  843.         }
  844.     }
  845.       else
  846.     error ("system: expecting string as first argument");
  847.  
  848.       if (! error_state)
  849.     {
  850. #if defined (__EMX__) && defined (OS2)
  851.       if (type == async || type == pm)
  852. #else
  853.       if (type == async)
  854. #endif
  855.         {
  856. #ifndef __EMX__
  857.           pid_t pid = fork ();
  858.  
  859.           if (pid < 0) 
  860.         error ("system: fork failed -- can't create child process");
  861.           else if (pid == 0)
  862.         {
  863.           system (cmd_str.c_str ());
  864.           exit (0);
  865.           retval(0) = 0.0;
  866.         }
  867.           else
  868.         retval(0) = (double) pid;
  869. #else
  870.           pid_t pid;
  871.           int p_mode;
  872. #ifdef OS2
  873.           if (type == pm)  p_mode = P_PM;
  874.           else             p_mode = P_NOWAIT;
  875. #else
  876.           p_mode = P_NOWAIT;
  877. #endif
  878.           pid = _IO_system (cmd_str.c_str (), p_mode);
  879.  
  880.           if (pid < 0)
  881.         error ("system: spawn failed -- can't create child process");
  882.           else
  883.         retval(0) = (double) pid;
  884. #endif
  885.         }
  886.       else if (return_output)
  887.         retval = run_command_and_return_output (cmd_str);
  888.       else
  889.         {
  890. #ifdef __EMX__
  891.            int status = _IO_system (cmd_str.c_str (), P_WAIT);
  892. #else
  893.           int status = system (cmd_str.c_str ());
  894. #endif
  895.  
  896.           // The value in status is as returned by waitpid.  If
  897.           // the process exited normally, extract the actual exit
  898.           // status of the command.  Otherwise, return 127 as a
  899.           // failure code.
  900.  
  901.           if (WIFEXITED (status))
  902.         status = WEXITSTATUS (status);
  903.  
  904.           retval = (double) status;
  905.         }
  906.     }
  907.     }
  908.   else
  909.     print_usage ("system");
  910.  
  911.   return retval;
  912. }
  913.  
  914. DEFALIAS (shell_cmd, system);
  915.  
  916. static SLStack<string> octave_atexit_functions;
  917.  
  918. void
  919. do_octave_atexit (void)
  920. {
  921.   while (! octave_atexit_functions.empty ())
  922.     {
  923.       octave_value_list fcn = octave_atexit_functions.pop ();
  924.  
  925.       feval (fcn, 0);
  926.     }
  927. }
  928.  
  929. DEFUN (atexit, args, ,
  930.   "atexit (NAME): register NAME as a function to call when Octave exits\n\
  931. \n\
  932. Functions are called with no arguments in the reverse of the order in\n\
  933. which they were registered with atexit()")
  934. {
  935.   octave_value_list retval;
  936.  
  937.   int nargin = args.length ();
  938.  
  939.   if (nargin == 1)
  940.     {
  941. #if defined (HAVE_ATEXIT) || defined (HAVE_ON_EXIT)
  942.       string arg = args(0).string_value ();
  943.  
  944.       if (! error_state)
  945.     octave_atexit_functions.push (arg);
  946.       else
  947.     error ("atexit: argument must be a string");
  948. #else
  949.       gripe_not_supported ("atexit");
  950. #endif
  951.     }
  952.   else
  953.     print_usage ("atexit");
  954.  
  955.   return retval;
  956. }
  957.  
  958. DEFUN (octave_config_info, args, ,
  959.   "octave_config_info (OPTION)\n\
  960. \n\
  961. If OPTION is a string, return the configuration information for the\n\
  962. specified option.\n\
  963. \n\
  964. With no arguments, return a structure containing configuration\n\
  965. information.")
  966. {
  967.   octave_value retval;
  968.  
  969. #if defined (WITH_DYNAMIC_LINKING) && (defined (WITH_DL) || defined (WITH_SHL))
  970.   bool octave_supports_dynamic_linking = true;
  971. #else
  972.   bool octave_supports_dynamic_linking = false;
  973. #endif
  974.  
  975.   Octave_map m;
  976.  
  977.   m ["default_pager"] = DEFAULT_PAGER;
  978.   m ["prefix"] = OCTAVE_PREFIX;
  979.   m ["exec_prefix"] = OCTAVE_EXEC_PREFIX;
  980.   m ["datadir"] = OCTAVE_DATADIR;
  981.   m ["dld"] = (double) octave_supports_dynamic_linking;
  982.   m ["libdir"] = OCTAVE_LIBDIR;
  983.   m ["bindir"] = OCTAVE_BINDIR;
  984.   m ["infodir"] = OCTAVE_INFODIR;
  985.   m ["fcnfiledir"] = OCTAVE_FCNFILEDIR;
  986.   m ["localfcnfiledir"] = OCTAVE_LOCALFCNFILEDIR;
  987.   m ["localstartupfiledir"] = OCTAVE_LOCALSTARTUPFILEDIR;
  988.   m ["startupfiledir"] = OCTAVE_STARTUPFILEDIR;
  989.   m ["localfcnfilepath"] = OCTAVE_LOCALFCNFILEPATH;
  990.   m ["archlibdir"] = OCTAVE_ARCHLIBDIR;
  991.   m ["localarchlibdir"] = OCTAVE_LOCALARCHLIBDIR;
  992.   m ["octfiledir"] = OCTAVE_OCTFILEDIR;
  993.   m ["localoctfilepath"] = OCTAVE_LOCALOCTFILEPATH;
  994.   m ["fcnfilepath"] = OCTAVE_FCNFILEPATH;
  995.   m ["imagepath"] = OCTAVE_IMAGEPATH;
  996.   m ["target_host_type"] = TARGET_HOST_TYPE;
  997.   m ["configure_options"] = config_opts;
  998.   m ["F77"] = F77;
  999.   m ["FFLAGS"] = FFLAGS;
  1000.   m ["FPICFLAG"] = FPICFLAG;
  1001.   m ["F2C"] = F2C;
  1002.   m ["F2CFLAGS"] = F2CFLAGS;
  1003.   m ["FLIBS"] = FLIBS;
  1004.   m ["CPPFLAGS"] = CPPFLAGS;
  1005.   m ["INCFLAGS"] = INCFLAGS;
  1006.   m ["CC"] = CC " " CC_VERSION;
  1007.   m ["CFLAGS"] = CFLAGS;
  1008.   m ["CPICFLAG"] = CPICFLAG;
  1009.   m ["CXX"] = CXX " " CXX_VERSION;
  1010.   m ["CXXFLAGS"] = CXXFLAGS;
  1011.   m ["CXXPICFLAG"] = CXXPICFLAG;
  1012.   m ["LDFLAGS"] = LDFLAGS;
  1013.   m ["LIBFLAGS"] = LIBFLAGS;
  1014.   m ["RLD_FLAG"] = RLD_FLAG;
  1015.   m ["CXXLIBS"] = CXXLIBS;
  1016.   m ["TERMLIBS"] = TERMLIBS;
  1017.   m ["LIBS"] = LIBS;
  1018.   m ["LEXLIB"] = LEXLIB;
  1019.   m ["LIBPLPLOT"] = LIBPLPLOT;
  1020.   m ["LIBDLFCN"] = LIBDLFCN;
  1021.   m ["DEFS"] = DEFS;
  1022.  
  1023.   int nargin = args.length ();
  1024.  
  1025.   if (nargin == 1)
  1026.     {
  1027.       string arg = args(0).string_value ();
  1028.  
  1029.       if (! error_state)
  1030.     retval = octave_value (m [arg.c_str ()]);
  1031.     }
  1032.   else if (nargin == 0)
  1033.     retval = octave_value (m);
  1034.   else
  1035.     print_usage ("octave_config_info");
  1036.  
  1037.   return retval;
  1038. }
  1039.  
  1040. #if defined (__GNUG__) && defined (DEBUG_NEW_DELETE)
  1041.  
  1042. int debug_new_delete = 0;
  1043.  
  1044. typedef void (*vfp)(void);
  1045. extern vfp __new_handler;
  1046.  
  1047. void *
  1048. __builtin_new (size_t sz)
  1049. {
  1050.   void *p;
  1051.  
  1052.   /* malloc (0) is unpredictable; avoid it.  */
  1053.   if (sz == 0)
  1054.     sz = 1;
  1055.   p = (void *) malloc (sz);
  1056.   while (p == 0)
  1057.     {
  1058.       (*__new_handler) ();
  1059.       p = (void *) malloc (sz);
  1060.     }
  1061.  
  1062.   if (debug_new_delete)
  1063.     cout << "__builtin_new: " << p << endl;
  1064.  
  1065.   return p;
  1066. }
  1067.  
  1068. void
  1069. __builtin_delete (void *ptr)
  1070. {
  1071.   if (debug_new_delete)
  1072.     cout << "__builtin_delete: " << ptr << endl;
  1073.  
  1074.   if (ptr)
  1075.     free (ptr);
  1076. }
  1077.  
  1078. #endif
  1079.  
  1080. static int
  1081. default_eval_print_flag (void)
  1082. {
  1083.   Vdefault_eval_print_flag = check_preference ("default_eval_print_flag");
  1084.  
  1085.   return 0;
  1086. }
  1087.  
  1088. void
  1089. symbols_of_toplev (void)
  1090. {
  1091.   DEFVAR (default_eval_print_flag, 1.0, 0, default_eval_print_flag,
  1092.     "If the value of this variable is nonzero, Octave will print the\n\
  1093. results of commands executed by eval() that do not end with semicolons.");
  1094. }
  1095.  
  1096. /*
  1097. ;;; Local Variables: ***
  1098. ;;; mode: C++ ***
  1099. ;;; End: ***
  1100. */
  1101.